package com.xjt.wx_admin.netty;


import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjt.wx_admin.constant.WxConstant;
import com.xjt.wx_admin.entity.User;
import com.xjt.wx_admin.entity.UserFriend;
import com.xjt.wx_admin.entity.dto.WebMsg;
import com.xjt.wx_admin.service.UserFriendService;
import com.xjt.wx_admin.service.UserService;
import com.xjt.wx_admin.util.RedisUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


@Configuration
@ChannelHandler.Sharable
@Slf4j
public class CoordinationSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    public Map<String, Channel> cmap = new HashMap<>();


    @Autowired
    UserService userService;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    UserFriendService userFriendService;

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("与客户端建立连接，通道开启！");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        String removeKey = null;
        for (String key : cmap.keySet()) {
            if (cmap.get(key).equals(ctx.channel())) {
                String uid = key.replace("user", "");
                User user = userService.getById(uid);
                if (user!=null){
                    System.out.println("用户id:"+uid+"下线..");
                    user.setOnline(0);
                    userService.updateById(user);
                }
                removeKey = key;
                break;
            }
        }
        cmap.remove(removeKey);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {

        //接收的消息
        WebMsg webMsg = JSONObject.parseObject(msg.text(), WebMsg.class);
        if (!verifyToken(webMsg.getToken())) {
//            处理验签失败
            ctx.writeAndFlush(new TextWebSocketFrame("fail auth"));
            return;
        }
        if (webMsg.getPing()!=null && webMsg.getPing().equals("ping")){
//            处理心跳检测
            ctx.writeAndFlush(new TextWebSocketFrame("pong"));
            return;
        }
        Integer type = webMsg.getType();
        switch (type){
            case 1:   // 登录
                websocketLogin(webMsg,ctx);
                break;
            case 2: // 发送对话消息
                send(webMsg);
                break;
            case 3:   // 请求进行视频通话
                call(webMsg);
                break;
            case 4:   // 对方回应通话
                response(webMsg);
                break;
            case 5:   //传递请求off
                askoff(webMsg);
                break;
            case 6:   //获取off
                getoff(webMsg);
                break;
            case 7:
                answer(webMsg);
                break;
            case 8:
                candidate(webMsg);
                break;
        }
        System.out.printf("收到客户端%s的数据：%s%n", ctx.channel().id(), msg.text());
    }

    private Boolean verifyToken(String token){
        String username;
        try {
            JWT jwt = JWTUtil.parseToken(token);
            username = (String) jwt.getPayload("userName");
        }catch (Exception e) {
            return false;
        }
        // 3、使用userId从redis中查询对应的LoginUser对象
        String loginUserJson = (String)redisUtil.get("login:" + username +":"+token);
        return loginUserJson != null;
    }

    private void answer(WebMsg webMsg) {
        String to = webMsg.getTo();
        if (cmap.containsKey("user"+to)){
            Channel channel = cmap.get("user" + to);
            WebMsg msg = WebMsg.builder()
                    .type(WxConstant.MsgType.ANSWER.getCode())
                    .uuid(UUID.randomUUID().toString())
                    .from(webMsg.getUid())
                    .message(webMsg.getMessage())
                    .build();
            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg)));
        }else {
            System.out.println("未登录");
        }
    }

    private void candidate(WebMsg webMsg) {
        String to = webMsg.getTo();
        if (cmap.containsKey("user"+to)){
            Channel channel = cmap.get("user" + to);
            WebMsg msg = WebMsg.builder()
                    .type(WxConstant.MsgType.CANDIDATE.getCode())
                    .uuid(UUID.randomUUID().toString())
                    .from(webMsg.getUid())
                    .message(webMsg.getMessage())
                    .build();
            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg)));
        }else {
            System.out.println("未登录");
        }
    }

    private void getoff(WebMsg webMsg) {
        String to = webMsg.getTo();
        if (cmap.containsKey("user"+to)){
            Channel channel = cmap.get("user" + to);
            WebMsg msg = WebMsg.builder()
                    .type(WxConstant.MsgType.GET_OFF.getCode())
                    .uuid(UUID.randomUUID().toString())
                    .from(webMsg.getUid())
                    .message(webMsg.getMessage())
                    .build();
            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg)));
        }else {
            System.out.println("未登录");
        }
    }


    private void askoff(WebMsg webMsg) {
        String to = webMsg.getTo();
        if (cmap.containsKey("user"+to)){
            Channel channel = cmap.get("user" + to);
            WebMsg msg = WebMsg.builder()
                    .type(WxConstant.MsgType.ASK_OFF.getCode())
                    .uuid(UUID.randomUUID().toString())
                    .from(webMsg.getUid())
                    .build();
            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg)));
        }else {
            System.out.println("未登录");
        }
    }

    private void response(WebMsg webMsg) {
        String to = webMsg.getTo();
        if (cmap.containsKey("user"+to)){
            Channel channel = cmap.get("user" + to);
            WebMsg msg = WebMsg.builder()
                    .type(WxConstant.MsgType.RESPONSE_CALL.getCode())
                    .uuid(UUID.randomUUID().toString())
                    .from(webMsg.getUid())
                    .build();
            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg)));
        }else {
            System.out.println("未登录");
        }
    }

    private void call(WebMsg webMsg) {
        String to = webMsg.getTo();
        if (cmap.containsKey("user"+to)){
            Channel channel = cmap.get("user" + to);
            WebMsg msg = WebMsg.builder()
                    .type(WxConstant.MsgType.VIDEO_CALL.getCode())
                    .uuid(UUID.randomUUID().toString())
                    .from(webMsg.getUid())
                    .build();
            channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg)));
        }else {
            System.out.println("未登录");
        }
    }

    private void send(WebMsg webMsg) {
        String to = webMsg.getTo();
        String from = webMsg.getFrom();
        UserFriend userFriend = userFriendService.getOne(Wrappers.<UserFriend>lambdaQuery()
                .eq(UserFriend::getFriendId, from)
                .eq(UserFriend::getUserId, to)
        );
        if (userFriend==null){
            WebMsg msg = WebMsg.builder()
                    .type(WxConstant.MsgType.EXCEPTION.getCode())
                    .message("当前用户不是的你好友")
                    .build();
            if (cmap.containsKey("user"+from)){
                Channel channel = cmap.get("user" + from);
                channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg)));
            }
        }else {
            if (cmap.containsKey("user"+to)){
                String formName = userFriend.getRemark();
                if (formName==null || formName.equals("")){
                    formName = userService.getById(from).getName();
                }
                Channel channel = cmap.get("user" + to);
                WebMsg msg = WebMsg.builder()
                        .type(WxConstant.MsgType.SEND_MSG.getCode())
                        .uuid(UUID.randomUUID().toString())
                        .message(webMsg.getMessage())
                        .from(formName)
                        .fromId(Long.valueOf(webMsg.getFrom()))
                        .build();
                channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg)));
            }else {
                System.out.println("未登录");
            }
        }

    }

    /**
     * websocket登录
     *
     * @param webMsg 消息实体
     * @param ctx    ctx
     */
    private void websocketLogin(WebMsg webMsg, ChannelHandlerContext ctx) {
        String uid = webMsg.getUid();
        if (cmap.containsKey("user"+uid)){
            log.info("发送下线通知...");
            Channel channel = cmap.get("user" + uid);
            WebMsg msg = WebMsg.builder()
                    .type(WxConstant.MsgType.PUSH_OFF_LINE.getCode())
                    .message("你的账号在其他端登录,你已被挤下线")
                    .build();
            channel.writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(msg)));
            channel.closeFuture();
        }
        cmap.put("user"+uid,ctx.channel());
        User user = userService.getById(uid);
        user.setOnline(1);
        userService.updateById(user);
        System.out.println(uid+"登录,在线人数："+cmap.size());
    }

}
